#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

// OpenSLES
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

#include "nobnak_study_opensles_Recorder.h"
#include "androidlog.h"
#include "SoundEngine.h"
#include "Recorder.h"
#include "Encoder.h"
#include "JNIUpstream.h"

#define USLEEP_TIME (100 * 1000)
// Buffer config
#define FRAME_NUMBERS (2)
#define RECORDER_FRAMES (16000)
#define MP3_BITRATE (64000)

// recorder
static Recorder *recorder;
static Encoder *encoder;
static JNIUpstream *upstream;
// Java VM
static JavaVM *vm;
static jobject callbackListener;
// thread
static pthread_t pthread_callbackWorker;


void *callbackWorker(void *arg) {
	while (true) {
		recorder->march();
		usleep(USLEEP_TIME);
	}
}

jint JNI_OnLoad(JavaVM* _vm, void* reserved) {
	JNIEnv *env;
	vm = _vm;
	jint result;
	result = vm->GetEnv((void**) &env, JNI_VERSION_1_6);
	if (result != JNI_OK)
		return -1;

	return JNI_VERSION_1_6;
}
// set callback listener
JNIEXPORT jboolean JNICALL Java_nobnak_study_opensles_Recorder_setListener(
		JNIEnv* env, jclass clazz, jobject obj) {
	try {
		upstream->setListener(env, obj);
	} catch(const char *e) {
		Log::d(e);
		return JNI_FALSE;
	}

	return JNI_TRUE;
}

// create the engine and output mix objects
JNIEXPORT jboolean JNICALL Java_nobnak_study_opensles_Recorder_createEngine(
		JNIEnv* env, jclass clazz) {
	SLresult result;

	SoundEngine *engine;
	try {
		engine = SoundEngine::get();
	} catch(const char *e) {
		Log::d(e);
		return JNI_FALSE;
	}

	return JNI_TRUE;
}
// shut down the native audio system
JNIEXPORT void JNICALL Java_nobnak_study_opensles_Recorder_shutdown(
		JNIEnv* env, jclass clazz) {
	if (recorder != NULL) {
		delete recorder;
		recorder = NULL;
	}

	SoundEngine::shutdown();
}

// create audio recorder
JNIEXPORT jboolean JNICALL Java_nobnak_study_opensles_Recorder_createAudioRecorder(
		JNIEnv* env, jclass clazz) {
	SoundEngine *engine;
	try {
		engine = SoundEngine::get();
	} catch(const char * e) {
		Log::d(e);
		return JNI_FALSE;
	}

	try {
		recorder = engine->makeRecorder(RECORDER_FRAMES, FRAME_NUMBERS);
		encoder = new Encoder(RECORDER_FRAMES, MP3_BITRATE, RECORDER_FRAMES);
		recorder->pipe(encoder);
		upstream = new JNIUpstream(vm);
		encoder->pipe(upstream);

		pthread_create(&pthread_callbackWorker, NULL, callbackWorker, NULL);
	} catch(const char *e) {
		Log::d(e);
		return JNI_FALSE;
	}

	return JNI_TRUE;
}
// stop recording interface
JNIEXPORT jboolean JNICALL Java_nobnak_study_opensles_Recorder_stopRecording(
		JNIEnv* env, jclass clazz) {
	if (recorder == NULL)
		return JNI_TRUE;
	try {
		recorder->stopRecording();
	} catch(const char *e) {
		Log::d(e);
		return JNI_FALSE;
	}
	return JNI_TRUE;
}

// set the recording state for the audio recorder
JNIEXPORT jboolean JNICALL Java_nobnak_study_opensles_Recorder_startRecording(
		JNIEnv* env, jclass clazz) {
	if (recorder == NULL)
		return JNI_FALSE;

	try {
		recorder->startRecording();
	} catch(const char *e) {
		Log::d(e);
		return JNI_FALSE;
	}

	return JNI_TRUE;
}

